/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pagrafo.genetico;

import java.util.ArrayList;
import java.util.Collections;
import pagrafo.grafo.Grafo;
import pagrafo.util.Vetor;

/**
 *
 * @author Fabricio
 */
public class Cromossomo implements Comparable {

    /**
     * O cromossomo em sí
     */
    public int[] v;
    private double score;
    private Grafo g;
    private int k;
    private double capacidade;

    /**
     * 
     */
    public Cromossomo(Grafo g, int k, double capacidade) {
        this.g = g;
        this.capacidade = capacidade;
        this.k = k;
        this.v = criaCromossomoAleatorio(g.sizeVertices(), k);
        this.score = calculaScore();
    }

    /**
     * Construtor do cromossomo a partir de uma cadeia de genes de entrada
     * @param g
     * @param ag
     * @param v 
     */
    public Cromossomo(Grafo g, int k, double capacidade, int[] v) {
        this.g = g;
        this.capacidade = capacidade;
        this.k = k;
        this.v = v;
        this.score = calculaScore();
    }

    public int compareTo(Object t) {
        return (int)(this.getScore() - ((Cromossomo) t).getScore());
    }

    private double calculaScore() {

        //Peso total em uma rota i
        double[] pesoRota = new double[k];
        double pesoTotal = 0;

        //Demanda total em uma rota i
        double[] demandaRota = new double[k];

        //O número do caminho que está sendo percorrido
        int n = 0;

        //Encontra os pesos e as demandas por caminho
        for (int i = 0; i < v.length -1; i++) {

            //System.out.println(v[i] + " " + v[i+1]);
            double peso = 0;
            peso = g.getPeso(v[i], v[i+1]);
            double demanda = g.getDemanda(v[i]);
            
            if (v[i] == 0 && i != 0) {
                n++;
            }
            
            pesoRota[n] += peso;

            demandaRota[n] += demanda;

            pesoTotal += peso;

        }

        //Considerar uma penalidade bem alta
        double penalidadeDemandaNaoAtendida = 0;

        for (int i = 0; i < demandaRota.length; i++) {
            if (demandaRota[i] > capacidade) {
                penalidadeDemandaNaoAtendida += demandaRota[i] - capacidade;
            }
        }

        int numeroInteracoes = 0;

        double penalidadeDeBalanceamentoDeDemanda = 0;
        for (int i = 0; i < demandaRota.length - 1; i++) {
            for (int j = i + 1; j < demandaRota.length; j++) {
                penalidadeDeBalanceamentoDeDemanda += Math.abs(demandaRota[i] - demandaRota[j]);
                numeroInteracoes++;
            }
        }

        double penalidadeDeBalanceamentoDePeso = 0;
        for (int i = 0; i < demandaRota.length - 1; i++) {
            for (int j = i + 1; j < demandaRota.length; j++) {
                penalidadeDeBalanceamentoDePeso += Math.abs(pesoRota[i] - pesoRota[j]);
            }
        }

        //Soma das requisições, se estourar a capacidade de um caminhão é penalizado, 
        //caminhos balanceados são melhores, tanto em peso quanto em capacidade,
        //Menor peso total melhor       
        //return pesoTotal * (penalidadeDemandaNaoAtendida + 1) / (k + g.sizeVertices() - 1) + (penalidadeDeBalanceamentoDeDemanda + penalidadeDeBalanceamentoDePeso) / numeroInteracoes;
        return pesoTotal * (penalidadeDemandaNaoAtendida + 1);
        //return pesoTotal;
    }

    public double getScore() {
        return score;
    }

//    private int[] criaCromossomoAleatorio(int numConsumer, int numRoute) {
//
//        int numZeros = numRoute + 1;
//        int tamanho = (numConsumer + numZeros);
//        int max = tamanho - 1;
//        int min = 1;
//        int c[] = new int[tamanho];
//
//
//        for (int i = 0; i < c.length; i++) {
//            c[i] = -1;
//        }
//
//        c[0] = 0;
//        c[max] = 0;
//        numZeros = numZeros - 2;
//
//        int i;
//
//        while (numZeros > 0) {
//            i = (int) (min + (int) (Math.random() * ((max - min) + 1)));
//            int ant = -1;
//            int prox = -1;
//
//            try {
//                ant = c[i - 1];
//            } catch (Exception e) {
//            }
//
//            try {
//                prox = c[i + 1];
//            } catch (Exception e) {
//            }
//
//            if (c[i] == -1 && ant != 0 && prox != 0) {
//                c[i] = 0;
//                numZeros--;
//            }
//        }
//
//        int consumidor = 1;
//
//        while (numConsumer > 0) {
//            i = (int) (min + (int) (Math.random() * ((max - min) + 1)));
//            if (c[i] == -1) {
//                c[i] = consumidor;
//                numConsumer--;
//                consumidor++;
//            }
//        }
//        //Para Teste
//        //System.out.print("Cromossomo: ");
//        //for (int m = 0; m < c.length; m++) {
//        //    System.out.print(c[m]);
//        //    System.out.print(",");
//        //}
//        //System.out.println("");
//        return c;
//    }

    public int[] getV() {
        return v;
    }

    public void setV(int[] v) {
        this.v = v;
    }
    
    private int[] criaCromossomoAleatorio(int n, int k) {

        int zeros = k - 2;
        int tamanho = (n + k);
        
        int[] genes = new int[tamanho];
        genes[0] = 0;
        genes[tamanho-1] = 0;
        
        boolean naoValido = true;
        
        while(naoValido){
        
            //Cria lista para sorteio e preenche com os valores
            ArrayList<Integer> roleta = new ArrayList<Integer>();
            for(int i = 0; i < n ; i++){
                roleta.add(Integer.valueOf(i));
            }
            for(int i = 0; i < zeros ; i++){
                roleta.add(Integer.valueOf(0));
            }
            
            //Teste
            //for(int i = 0; i < roleta.size(); i++){
            //    System.out.print(roleta.get(i) + " ");
            //}
            //System.out.println("");

            //Preenche os genes com os valores da roleta
            Collections.shuffle(roleta);
            for(int i = 0; i < roleta.size() ; i++){
                genes[i+1] = roleta.get(i).intValue();
            }

            boolean anteriorZero = false;
            boolean controleValido = true;
            for(int i = 0; i < genes.length ; i++){
                
                //Caso o atual e o anterior sejam zeros o cromossomo não é válido
                if(genes[i] == 0 && anteriorZero){
                    controleValido = false;
                    break;
                }
                
                if(genes[i] == 0){
                    anteriorZero = true;
                }else{
                    anteriorZero = false;
                }
            }
            
            if(controleValido){
                naoValido = false;
            }
        }
        
        //Para Teste
        //System.out.print("Cromossomo: ");
        //for (int m = 0; m < genes.length; m++) {
        //    System.out.print(genes[m]);
        //    System.out.print(",");
        //}
        //System.out.println("");
        
        return genes;
    }

    public Grafo getGrafo() {
        return g;
    }

    public double getCapacidade() {
        return capacidade;
    }

    public int getK() {
        return k;
    }
    
    public static String imprimirCromossomo(Cromossomo cromossomo){
        String s = new String();       
        for(int i = 0; i < cromossomo.v.length; i++){
            s += cromossomo.v[i] + ",";
        }
        return s;
    }
    
    
}
